struct istream *input;
struct ostream *output;
size_t max_line_size;
+ unsigned int list_count_limit;
enum imap_parser_flags flags;
/* reset by imap_parser_reset(): */
ARRAY_TYPE(imap_arg_list) root_list;
ARRAY_TYPE(imap_arg_list) *cur_list;
struct imap_arg *list_arg;
+ unsigned int list_count;
enum arg_parse_type cur_type;
size_t cur_pos; /* parser position in input buffer */
struct imap_parser *
imap_parser_create(struct istream *input, struct ostream *output,
size_t max_line_size,
- const struct imap_parser_params *params ATTR_UNUSED)
+ const struct imap_parser_params *params)
{
struct imap_parser *parser;
parser->input = input;
parser->output = output;
parser->max_line_size = max_line_size;
+ if (params != NULL && params->list_count_limit > 0)
+ parser->list_count_limit = params->list_count_limit;
+ else
+ parser->list_count_limit = UINT_MAX;
p_array_init(&parser->root_list, parser->pool, LIST_INIT_COUNT);
parser->cur_list = &parser->root_list;
p_array_init(&parser->root_list, parser->pool, LIST_INIT_COUNT);
parser->cur_list = &parser->root_list;
parser->list_arg = NULL;
+ parser->list_count = 0;
parser->cur_type = ARG_PARSE_NONE;
parser->cur_pos = 0;
parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
return FALSE;
}
+ if (parser->list_count >= parser->list_count_limit) {
+ parser->error_msg = "Too many '('";
+ parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
+ return FALSE;
+ }
+ parser->list_count++;
arg = imap_arg_create(parser);
arg->type = IMAP_ARG_EOL;
};
struct imap_parser_params {
+ /* How many open lists ('(' chars) to allow before faililng the parsing.
+ 0 means unlimited. This is mainly used to prevent excessive memory
+ usage in imap-login process. In imap process there are many other
+ ways to increase memory usage, so we let the max_line_size be the
+ only limit. */
+ unsigned int list_count_limit;
};
struct imap_parser;
#include "lib.h"
#include "istream.h"
+#include "istream-chain.h"
#include "imap-parser.h"
#include "test-common.h"
test_end();
}
+static void test_imap_parser_list_limit(void)
+{
+ struct {
+ const char *input;
+ int ret;
+ } tests[] = {
+ { "(())\r\n", 1 },
+ { "((()))\r\n", -1 },
+ };
+ struct istream_chain *chain;
+ struct istream *chain_input;
+ struct imap_parser *parser;
+ const struct imap_arg *args;
+
+ test_begin("imap parser list limit");
+ struct imap_parser_params params = {
+ .list_count_limit = 2,
+ };
+
+ for (unsigned int i = 0; i < N_ELEMENTS(tests); i++) {
+ chain_input = i_stream_create_chain(&chain, SIZE_MAX);
+ parser = imap_parser_create(chain_input, NULL, 1024, ¶ms);
+
+ for (unsigned int j = 0; j < 2; j++) {
+ struct istream *input =
+ test_istream_create(tests[i].input);
+ i_stream_chain_append(chain, input);
+ i_stream_unref(&input);
+
+ (void)i_stream_read(chain_input);
+
+ test_assert_cmp(imap_parser_read_args(parser, 0, 0, &args), ==, tests[i].ret);
+ /* skip over CRLF */
+ i_stream_skip(chain_input, i_stream_get_data_size(chain_input));
+
+ /* make sure parser reset works */
+ imap_parser_reset(parser);
+ }
+ imap_parser_unref(&parser);
+ i_stream_destroy(&chain_input);
+ }
+ test_end();
+}
+
static void test_imap_parser_read_tag_cmd(void)
{
enum read_type {
static void (*const test_functions[])(void) = {
test_imap_parser_crlf,
test_imap_parser_partial_list,
+ test_imap_parser_list_limit,
test_imap_parser_read_tag_cmd,
NULL
};